﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Nha3D
{
    public partial class frmNha3D : Form
    {
        struct wireframe
        {
            public int numEdges, numVerts;
            public point3D[] vert;
            public int[,] edge;
        }
        struct point3D
        {
            public double x, y, z;
        }
        struct point2D
        {
            public double x, y;
        }
        const float goc=(float)(5*Math.PI/180);
        double phi = Math.PI * 10 / 180, teta = Math.PI * 30 / 180;
        //================
        Bitmap b;
        Graphics bg;
        Pen p;
        Color b1Back, b1Fore;
        // vi tri he toa do
        int Xo, Ho;
        //wireframe Ngoi nha
        wireframe w;
        void initwireframe(ref wireframe w)
        {
         
            w.numVerts = 10;
            w.numEdges = 17;
            w.edge = new int[w.numEdges, 2];
            w.vert = new point3D[w.numVerts];
           
            w.vert[0].x = 0 ; w.vert[0].y = 0 ; w.vert[0].z =0;
            w.vert[1].x = 80; w.vert[1].y = 0; w.vert[1].z = 0;
            //w.vert[2].x = 80; w.vert[2].y = 0; w.vert[2].z = 80;
            //w.vert[3].x = 0; w.vert[3].y = 0; w.vert[3].z = 80;

            //w.vert[4].x = 0; w.vert[4].y = 80; w.vert[4].z = 80;
            //w.vert[5].x = 80; w.vert[5].y = 80; w.vert[5].z = 80;
            //w.vert[6].x = 80; w.vert[6].y = 80; w.vert[6].z = 0;
            //w.vert[7].x = 0; w.vert[7].y = 80; w.vert[7].z = 0;
            //w.vert[8].x = 0; w.vert[8].y = 120; w.vert[8].z = 40;
            //w.vert[9].x = 80; w.vert[9].y = 120; w.vert[9].z = 40;

            //w.edge[0, 0] = 0; w.edge[0, 1] = 1;
            //w.edge[1, 0] = 1; w.edge[1, 1] = 2;
            //w.edge[2, 0] = 2; w.edge[2, 1] = 3;
            //w.edge[3, 0] = 0; w.edge[3, 1] = 3;
            //w.edge[4, 0] = 0; w.edge[4, 1] = 7;
            //w.edge[5, 0] = 1; w.edge[5, 1] = 6;
            //w.edge[6, 0] = 2; w.edge[6, 1] = 5;
            //w.edge[7, 0] = 3; w.edge[7, 1] = 4;

            //w.edge[8, 0] = 4; w.edge[8, 1] = 8;
            //w.edge[9, 0] = 8; w.edge[9, 1] = 7;
            //w.edge[10, 0] = 5; w.edge[10, 1] = 9;

            //w.edge[11, 0] = 9; w.edge[11, 1] = 6;
            //w.edge[12, 0] = 8; w.edge[12, 1] = 9;
            //w.edge[13, 0] = 4; w.edge[13, 1] = 5;
            //w.edge[14, 0] = 5; w.edge[14, 1] = 6;
            //w.edge[15, 0] =6; w.edge[15, 1] = 7;
            //w.edge[16, 0] = 4; w.edge[16, 1] = 7;
           
            
        }
        void myLine(point2D p1, point2D p2, Graphics b1g)
        {
            p1.y = Ho - p1.y; p1.x += Xo;
            p2.y = Ho - p2.y; p2.x += Xo;
            b1g.DrawLine(p, (float)p1.x, (float)p1.y, (float)p2.x, (float)p2.y);
        }
        point2D chieuSSoxy(point3D p)
        {
            point2D q;
            q.x = p.x;
            q.y = p.y;
            return q;
        }
        void veWireframe(wireframe w, Graphics g)
        {
            point2D q1, q2;
            point3D p1, p2;
            for (int i = 0; i < w.numEdges; i++)
            {
                p1 = w.vert[w.edge[i, 0]];
                p2 = w.vert[w.edge[i, 1]];
                q1 = chieuSSoxy(p1); q2 = chieuSSoxy(p2);
                myLine(q1, q2, g);
            }
        }
        point3D xoayDiemOX(point3D p, float a)
        {
            point3D q;
            q.y = p.y * Math.Cos(a) - p.z * Math.Sin(a);
            q.z = p.y * Math.Sin(a) + p.z * Math.Cos(a);
            q.x = p.x;
            return q;
        }
        point3D xoayDiemOY(point3D p, float a)
        {
            point3D q;
            q.z = p.z * Math.Cos(a) - p.x * Math.Sin(a);
            q.x = p.z * Math.Sin(a) + p.x * Math.Cos(a);
            q.y = p.y;
            return q;
        }
        point3D xoayDiemOZ(point3D p, float a)
        {
            point3D q;
            q.x = p.x * Math.Cos(a) - p.y * Math.Sin(a);
            q.y = p.x * Math.Sin(a) + p.y * Math.Cos(a);
            q.z = p.z;
            return q;
        }
        //xoay wireframe
        void xoayWireframeOX(ref wireframe w, float a)
        {
            for (int i = 0; i < w.numVerts; i++)
                w.vert[i] = xoayDiemOX(w.vert[i], a);
        }
        void xoayWireframeOY(ref wireframe w, float a)
        {
            for (int i = 0; i < w.numVerts; i++)
                w.vert[i] = xoayDiemOY(w.vert[i], a);
        }
        void xoayWireframeOZ(ref wireframe w, float a)
        {
            for (int i = 0; i < w.numVerts; i++)
                w.vert[i] = xoayDiemOZ(w.vert[i], a);
        }
        public frmNha3D()
        {
            InitializeComponent();
            b = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height);
            bg = Graphics.FromImage(b);
            b1Back = Color.LightYellow;
            b1Fore = Color.Red;
            p = new Pen(b1Fore);
            Xo = b.Width / 2;
            Ho = b.Height /2;
            initwireframe(ref w);
            vePC_tongQuat(w, 300,phi, teta);
        }
        //Phuong phap chieu phoi canh
        void DoiHeToaDo(ref point3D p1, float R, double phi, double teta)
        {
            double x = p1.x, y = p1.y, z = p1.z;
            p1.x = Math.Round(-x * Math.Sin(teta) + y * Math.Cos(teta));
            p1.y = Math.Round(-x * Math.Cos(teta) * Math.Sin(phi) - y * Math.Sin(teta) * Math.Sin(phi) + z * Math.Cos(phi));
            p1.z = Math.Round(-x * Math.Cos(teta) * Math.Cos(phi) - y * Math.Sin(teta) * Math.Cos(phi) - z * Math.Sin(phi) + R);

        }

        void vePC_tongQuat(wireframe w, int E, double phi, double teta)
        {
            double x1, y1, x2, y2;
            double t;
            point3D p;
            for (int i = 0; i < w.numEdges; i++)
            {
                p = w.vert[w.edge[i, 0]];

                DoiHeToaDo(ref p, E, phi, teta);
                t = (double)E / p.z;
                x1 = Math.Round(p.x * t);
                y1 = Math.Round(p.y * t);
                point2D p1; p1.x = x1; p1.y = y1;

                p = w.vert[w.edge[i, 1]];

                DoiHeToaDo(ref p, E, phi, teta);
                t = (double)E / p.z;
                x2 = Math.Round(p.x * t);
                y2 = Math.Round(p.y * t);

                point2D p2; p2.x = x2; p2.y = y2;
                myLine(p1, p2, bg);
            }
            return;
        }
        private void Form1_Paint(object sender, PaintEventArgs e)
        {

            Graphics g = e.Graphics;
            g.DrawImageUnscaled(b,0,0);
        }

        private void frmNha3D_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.X:
                    //quay ox
                    xoayWireframeOX(ref w, goc);
                    bg.Clear(b1Back);
                    vePC_tongQuat(w, 200, phi, teta);
                    this.Invalidate();
                    break;
                case Keys.Y:
                    //quay oy
                    xoayWireframeOY(ref w, goc);
                    bg.Clear(b1Back);
                    vePC_tongQuat(w, 200, phi, teta);
                    this.Invalidate();
                    break;
                case Keys.Z:
                    //quay ox
                    xoayWireframeOZ(ref w, goc);
                    bg.Clear(b1Back);
                    vePC_tongQuat(w, 200, phi, teta);
                    this.Invalidate();
                    break;
            }
        }
    }
}
